<template>
  <div id="content" @contextmenu.prevent.stop="showContextMenu($event, null, -1)"
    :style="{ opacity: isLoading ? 0 : 1 }" style="transition: opacity 0.2s linear;" @click="closeContextMenu">

    <!-- 网格布局 -->
    <GridLayout v-model:layout="layout" :ref="setLayoutRef" :col-num="colNum" :row-height="rowHeight" :margin="[30, 30]"
      :cols="{ lg: colNum, md: colNum, sm: colNum, xs: colNum, xxs: colNum }" :max-rows="maxRows" :is-draggable="true"
      :prevent-collision="true" :is-resizable="true" :vertical-compact="false" :use-css-transforms="true"
      @layout-ready="layOutReady">

      <!-- 网格项 -->
      <GridItem v-for="(item, index) in layout" :key="item.i" :ref="e => setItemRef(item, e)" :x="item.x" :y="item.y"
        :w="item.w" :h="item.h" :i="item.i" :minW="item.minW ?? 2" :minH="item.minH ?? 2" :maxH="item.maxH"
        :maxW="item.maxW" :is-resizable="!!item.isResizable"
        @contextmenu.prevent.stop="showContextMenu($event, item, index)" @move="moveEvent" @moved="movedEvent"
        @resized="resizedEvent(index)">
        <a-component v-if="item.component === 'time'" :key="item.key" :data="item.key">
          <time-component></time-component>
        </a-component>
        <a-component v-if="item.component === 'plane'" :key="item.key">
          <plane-component></plane-component>
        </a-component>
        <a-component v-if="item.component === 'news'" :key="item.key">
          <news-component></news-component>
        </a-component>
        <a-component v-if="item.component === 'weather'" @click.stop="toMsnWeather" :key="item.key">
          <weather-component @weather-change="weatherChange"></weather-component>
        </a-component>
        <a-component v-if="item.component === 'search'" :background="''" :border="false" :over-hide="false"
          :key="item.key">
          <search-component></search-component>
        </a-component>
        <a-component v-if="item.component === 'use-history'" :background="''" :border="false" :over-hide="false"
          :key="item.key">
          <use-history-component></use-history-component>
        </a-component>
        <date-component v-if="item.component === 'date'" :title="imgData.title + ' ' + imgData.copyright"
          :key="item.key"></date-component>

        <a-component class="app" :class="{ 'checked': contextMenu.app && item.i === contextMenu.app.i }"
          v-if="item.component === 'app'" :title="item.title" @click.stop="openUrl(item.url, $event)" :border="true">
          <img class="app-icon" v-if="!item.appUrl" :src="'https://api.afmax.cn/so/ico/index.php?r=' + item.url"
            alt="" />
          <img class="app-icon" v-else :src="item.appUrl" alt="" />
        </a-component>
      </GridItem>
    </GridLayout>

    <!-- 右键菜单 -->
    <transition name="a-dialog-fade">
      <div v-if="contextMenu.visible" class="context-menu"
        :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }" @click.stop>
        <ul class="menu-list">
          <li v-if="!contextMenu.app" class="item" @click="onMenuAddAction(-1)">添加快捷应用</li>
          <li v-if="contextMenu.app?.component === 'app'" class="item" @click="onMenuAddAction(contextMenu.index)">
            编辑快捷方式</li>
          <li v-if="contextMenu.app" class="item error" @click="onMenuDeleteAction">删除{{ getDeleteLabel(contextMenu.app)
          }}
          </li>
          <li class="item" @click="settingDialog.visible = true; contextMenu.visible = false">系统设置</li>
        </ul>
      </div>
    </transition>

    <!-- 添加快捷图标对话框 -->
    <a-dialog v-model="addDialog.visible" :shake="!!addDialog.errorMessage">
      <div class="dialog-title">添加快捷应用</div>
      <div class="dialog-body">
        <div style="margin-bottom:8px;">
          <label>名称：</label>
          <input class="input" v-model="addDialog.name" maxlength="20" placeholder="最多20个字" />
        </div>
        <div style="margin-bottom:8px;">
          <label>地址：</label>
          <input class="input" v-model="addDialog.url" maxlength="400" placeholder="跳转地址" />
        </div>
        <div style="margin-bottom:8px;">
          <label>图标：</label>
          <input class="input" v-model="addDialog.icon" maxlength="400" placeholder="图标地址" />
        </div>
        <div v-if="addDialog.errorMessage" class="error-message">{{ addDialog.errorMessage }}</div>
      </div>
      <div class="dialog-footer">
        <button class="button" @click.stop="addDialog.visible = false">取消</button>
        <button class="button btn-primary" @click.stop="addQuickIcon">确定</button>
      </div>
    </a-dialog>

    <!-- 删除确认对话框 -->
    <a-dialog v-model="delDialog.visible">
      <div class="dialog-title">删除</div>
      <div>确认删除 {{
        delDialog.app && delDialog.app.component === 'app' ? delDialog.app.title ?? '快捷当时' : '小组件'
      }} 吗？
      </div>
      <div class="dialog-footer">
        <button class="button" @click.stop="delDialog.visible = false">取消</button>
        <button class="button btn-error" @click.stop="delApp">确定</button>
      </div>
    </a-dialog>

    <!-- 系统设置 -->
    <transition name="a-dialog-fade">
      <div v-if="settingDialog.visible" class="a-dialog-mask" @click="settingDialog.visible = false"
        @contextmenu.prevent.stop="" style="align-items: end;">
        <div class="settings-container" style="max-width: 100%;">
          <template v-if="layoutNotUse.length > 0">
            <div class="settings-header">拖拽小组件可纺织桌面</div>
            <div class="settings-body" style="max-width: 100%;" @click.stop="">
              <swiper :modules="[Navigation, Mousewheel]" :slides-per-view="'auto'" mousewheel
                :touchStartPreventDefault="false" style="padding: 0 40px;">
                <swiper-slide v-for="item in layoutNotUse" :key="item.i" style="width: auto;">
                  <div class="drop-app" draggable="true" @dragstart.stop="dropMinP(item)" @drag.stop="drag"
                    @dragend.stop="dragend">
                    <div v-if="item.appUrl"
                      style="background-color:var(--content-background-color);border-radius: 16px;height: 50px;width: 50px;padding: 10px;box-sizing: border-box;">
                      <img class="setting-img" :src="item.appUrl" alt="" />
                    </div>
                    <img v-else class="setting-img component" :src="item.minPic" alt=""
                      style="border-radius: 16px;height: 50px;" />
                    <div style="color: #eee;">{{ item.title }}</div>
                  </div>
                </swiper-slide>
              </swiper>
            </div>
          </template>
          <div class="setting-form" @click.stop="">
            <div class="item">
              <div>天气背景：</div>
              <div style="margin-left: 10px;">
                <div style="display: flex;align-items: start;">
                  <div class="radio-group">
                    <div class="radio-item"
                      :class="{ 'checked': settingDialog.data.weatherBg === 'auto' || settingDialog.data.weatherBg === '' }"
                      @click="changeWeatherBg('auto')">自动</div>
                    <div class="radio-item" :class="{ 'checked': settingDialog.data.weatherBg === '小雨' }"
                      @click="changeWeatherBg('小雨')">小雨</div>
                    <div class="radio-item" :class="{ 'checked': settingDialog.data.weatherBg === '中雨' }"
                      @click="changeWeatherBg('中雨')">中雨</div>
                    <div class="radio-item" :class="{ 'checked': settingDialog.data.weatherBg === '大雨' }"
                      @click="changeWeatherBg('大雨')">大雨</div>
                    <div class="radio-item" :class="{ 'checked': settingDialog.data.weatherBg === 'close' }"
                      @click="changeWeatherBg('close')">关闭</div>
                  </div>
                </div>
                <span style="font-size: 12px;color: var(--font-second-color);margin-top: 4px;">自动模式需要桌面添加天气组件哦</span>
              </div>
            </div>
            <div class="item">
              <div>主题颜色：</div>
              <a-switch :checked="settingDialog.data.cap === 'dark'" class="setting-item" @change="changeTheme"
                color="#000" style="margin: 0 10px;"></a-switch>
              <div> {{ settingDialog.data.cap === 'dark' ? '暗色' : '亮色' }}</div>
            </div>
          </div>
          <div style="margin-top: 10px;color: #eee;">AWork - {{ common.version }}</div>
          <div style="margin-top: 4px;color: #eee;">Author - IceFire</div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'a-grid',
}
</script>
<script setup>
// 引入 Vue 相关模块
import { ref, reactive, onMounted, onBeforeUnmount, nextTick, defineProps, defineEmits } from 'vue';
import { GridLayout, GridItem } from 'vue-grid-layout-v3';

// 引入组件
import AComponent from "@/home/common/a-component.vue";
import ADialog from "@/components/a-dialog.vue";
import ASwitch from "@/components/a-switch.vue";
import TimeComponent from "@/home/components/time.vue";
import DateComponent from "@/home/components/date.vue";
import PlaneComponent from "@/home/components/plane/plane.vue";
import UseHistoryComponent from "@/home/components/use-history/use-history.vue";
import NewsComponent from "@/home/components/news/news.vue";
import WeatherComponent from "@/home/components/weather.vue";
import SearchComponent from "@/home/components/search.vue";
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation, Mousewheel } from 'swiper/modules'; // 引入 Mousewheel 模块
import 'swiper/css';
import 'swiper/css/navigation';

// 引入工具库
import common from "@/lib/common";
import apps from "@/lib/apps";
import { storage } from "@/lib/storage";
import { bus } from "@/lib/bus"; // 消息总线

// 定义组件属性和事件
const emit = defineEmits(['weatherChange']);
defineProps(['imgData']);
// 定义响应式状态
const state = reactive({
  colNum: 44,
  layoutRef: {},
  itemRefs: {},
});
const layout = ref([]);
const layoutNotUse = ref([]);
const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0,
  index: -1,
  app: undefined,
});
const isLoading = ref(true);
const isDragging = ref(false);
const maxRows = ref(23);
const colNum = ref(44);
const rowHeight = ref(10);
const delDialog = reactive({ visible: false, index: -1, app: {} });
const settingDialog = reactive({ visible: false, data: { cap: 'light', weatherBg: "auto" } });
const addDialog = ref({ visible: false, name: '', icon: '', url: '', errorMessage: '', index: -1 });
const mouseXY = { x: null, y: null };
const DragPos = ref({ x: null, y: null, w: 4, h: 4, i: null });

// 初始化网格大小
function initSize() {
  const clientWidth = document.body.clientWidth;
  const clientHeight = document.body.clientHeight;
  maxRows.value = Math.floor(clientHeight / (rowHeight.value + 30));
  colNum.value = Math.floor((clientWidth - 30) / (rowHeight.value + 30));
  state.colNum = colNum.value
  storage.get('layout').then((storedLayout) => {
    if (storedLayout) {
      layout.value = JSON.parse(storedLayout);
    }
    initLayout();
  });
  storage.set('layoutSize', JSON.stringify({
    w: colNum.value,
    h: maxRows.value,
  }));
}

// 初始化布局
function initLayout() {
  apps.forEach((item) => {
    if (colNum.value > 46 && item.x + item.w > colNum.value / 2) {
        item.x = item.x + (colNum.value - 46);
      }
  })
  if (layout.value.length > 0) {
    // 更新布局
    layout.value = layout.value.map(item => {
      if (item.y + item.h > maxRows.value) {
        item.y = maxRows.value - item.h;
      }
      if (item.x + item.w > colNum.value) {
        item.x = colNum.value - item.w;
      }
      return item;
    });
  } else {
    layout.value = [];
  }
  storage.get("versionNumber").then(r => {
    let versionNumber = 0;
    try {
      versionNumber = parseInt(r ?? 0);
    } catch (e) {
      versionNumber = 0;
    }
    if (common.versionNumber >= 1 && versionNumber < 1) {
      layout.value = apps
      saveLayout();
      storage.set("versionNumber", common.versionNumber)
    }
    if (common.versionNumber > versionNumber) {
      findNoUseLayout();
      storage.set("versionNumber", common.versionNumber)
      return
    }
  });
}

// 保存布局
function saveLayout() {
  storage.set("layout", JSON.stringify(layout.value));
  findNoUseLayout();
}

function findNoUseLayout() {
  let existlayout = {}
  layout.value.forEach((item) => {
    existlayout[item.i] = 1;
  });
  layoutNotUse.value = [];
  apps.forEach((item) => {
    if (!existlayout[item.i]) {
      layoutNotUse.value.push(item);
    }
  });
}

// 跳转到 MSN 天气
function toMsnWeather() {
  if (isDragging.value) {
    return
  }
  window.open('https://www.msn.cn/zh-cn/weather/', '_blank');
}

// 显示右键菜单
function showContextMenu(e, item, idx) {
  contextMenu.x = Math.min(e.clientX, window.innerWidth - 140);
  contextMenu.y = Math.min(e.clientY, window.innerHeight - 100);
  contextMenu.app = item || null;
  contextMenu.index = idx ?? -1;
  contextMenu.visible = true;
}

// 关闭菜单
function closeContextMenu() {
  contextMenu.visible = false;
  contextMenu.app = {}
}

// 天气变化事件
function weatherChange(e) {
  emit('weatherChange', e)
}

// 打开 URL
function openUrl(url, event) {
  if (isDragging.value) {
    return
  }
  if (event && (event.ctrlKey || event.metaKey)) {
    window.open(url, '_blank');
  } else {
    window.open(url, '_self');
  }
}

// 布局准备完成
function layOutReady() {
  nextTick(() => {
    setTimeout(() => {
      isLoading.value = false;
    }, 250);
  });
}

// 调整大小事件
function resizedEvent(index) {
  bus.emit('resize-component', layout.value[index].component); // 通过消息总线通知其他组件
  saveLayout()
}

// 移动事件
function moveEvent() {
  isDragging.value = true
}

// 移动结束事件
function movedEvent() {
  setTimeout(() => {
    isDragging.value = false
    saveLayout()
  }, 500)
}

// 删除应用
function delApp() {
  layout.value.splice(delDialog.index, 1);
  delDialog.visible = false;
  saveLayout();
}

// 右键菜单删除操作
function onMenuDeleteAction() {
  delDialog.visible = true;
  delDialog.index = contextMenu.index;
  delDialog.app = contextMenu.app;
  contextMenu.visible = false;
  contextMenu.app = {};
}

// 右键菜单添加/编辑操作
function onMenuAddAction(index) {
  contextMenu.visible = false;
  addDialog.value = {
    visible: true,
    index: index,
    name: contextMenu.app ? contextMenu.app.title : '',
    icon: contextMenu.app ? contextMenu.app.appUrl : '',
    url: contextMenu.app ? contextMenu.app.url : ''
  }
  contextMenu.app = {}
}

// 切换主题
function changeTheme(e) {
  settingDialog.data.cap = e ? 'dark' : 'light';
  document.documentElement.setAttribute('theme-mode', settingDialog.data.cap);
  changeSetting();
}

function changeWeatherBg(bg) {
  settingDialog.data.weatherBg = bg;
  changeSetting();
}

// 改变设置
function changeSetting() {
  storage.set('setting', JSON.stringify(settingDialog.data))
  bus.emit('setting-changed', settingDialog.data.cap); // 通过消息总线通知其他组件
}

// 添加快捷图标
function addQuickIcon() {
  if (!addDialog.value.name) {
    addDialog.value.errorMessage = '名称不能为空';
    return;
  }
  if (!addDialog.value.url) {
    addDialog.value.errorMessage = '地址不能为空';
    return;
  }
  if (addDialog.value.index != null && addDialog.value.index >= 0) {
    layout.value[addDialog.value.index].title = addDialog.value.name;
    layout.value[addDialog.value.index].url = addDialog.value.url;
    layout.value[addDialog.value.index].appUrl = addDialog.value.icon;
  } else {
    let clientWidth = window.document.body.clientWidth
    let clientHeight = window.document.body.clientHeight

    layout.value.push({
      i: layout.value.length,
      x: parseInt(colNum.value * (contextMenu.x / clientWidth)),
      y: parseInt(maxRows.value * (contextMenu.y / clientHeight)),
      w: 2,
      h: 2,
      static: false,
      system: false,
      component: 'app',
      appUrl: addDialog.value.icon ? addDialog.value.icon : '/assets/app-logo/app.svg',
      url: addDialog.value.url,
      title: addDialog.value.name,
      isResizable: false
    });
  }
  addDialog.value.visible = false;
  saveLayout();
}

// 鼠标拖拽事件
document.addEventListener('dragover', (e) => {
  mouseXY.x = e.clientX;
  mouseXY.y = e.clientY;
}, false);

function dropMinP(layout) {
  DragPos.value = layout
}

async function drag() {
  settingDialog.visible = false
  const parentRect = document.getElementById('content').getBoundingClientRect();
  let mouseInGrid = false;
  if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
    mouseInGrid = true;
  }
  if (mouseInGrid === true && (layout.value.findIndex(item => item.i === 'drop')) === -1) {
    layout.value.push({
      x: (layout.value.length * 2) % (state.colNum || 12),
      y: layout.value.length + (state.colNum || 12), // puts it at the bottom
      w: DragPos.value.w,
      h: DragPos.value.h,
      i: 'drop',
    });
    await nextTick();
  }
  if (!state.itemRefs?.drop) {
    return;
  }
  const index = layout.value.findIndex(item => item.i === 'drop');
  if (index !== -1) {
    if (state.itemRefs?.drop?.el?.style) {
      state.itemRefs.drop.el.style.display = 'none';
    }
    const itemRef = state.itemRefs.drop;
    const new_pos = itemRef.calcXY(mouseXY.y - parentRect.top, mouseXY.x - parentRect.left);
    if (mouseInGrid === true) {
      state.layoutRef.emitter.emit('dragEvent', ['dragstart', 'drop', new_pos.x, new_pos.y, DragPos.value.h, DragPos.value.w]);
      DragPos.value.x = layout.value[index].x;
      DragPos.value.y = layout.value[index].y;
    }
    if (mouseInGrid === false) {
      state.layoutRef.emitter.emit('dragEvent', ['dragend', 'drop', new_pos.x, new_pos.y, DragPos.value.h, DragPos.value.w]);
      layout.value = layout.value.filter(obj => obj.i !== 'drop');
      await nextTick();
    }
  }
}

async function dragend() {
  const parentRect = document.getElementById('content').getBoundingClientRect();
  let mouseInGrid = false;
  if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
    mouseInGrid = true;
  }
  if (mouseInGrid === true) {
    state.layoutRef.emitter.emit('dragEvent', ['dragend', 'drop', DragPos.value.x, DragPos.value.y, DragPos.value.h, DragPos.value.w]);
    layout.value = layout.value.filter(obj => obj.i !== 'drop');
    layout.value.push(DragPos.value);
    await nextTick();
    state.layoutRef.emitter.emit('dragEvent', ['dragend', layout.value.length, DragPos.value.x, DragPos.value.y, DragPos.value.h, DragPos.value.w]);
    saveLayout();
  }
}

// 设置网格项引用
function setItemRef(item, e) {
  state.itemRefs[item.i] = e;
}

// 设置布局引用
function setLayoutRef(e) {
  state.layoutRef = e;
}

// 组件挂载后
onMounted(() => {
  window.addEventListener('resize', initSize);
  nextTick(initSize);
  storage.get('setting').then((res) => {
    if (res) {
      settingDialog.data = JSON.parse(res);
    }
  });
});

// 组件卸载前
onBeforeUnmount(() => {
  window.removeEventListener('resize', initSize);
});

// 定义 getDeleteLabel 方法，用于动态生成删除项的标签
function getDeleteLabel(app) {
  if (app.component === 'app') {
    return '快捷方式';
  } else {
    return '小组件';
  }
}

</script>

<style scoped lang="less">
/deep/ .app .c-content:hover,
/deep/ .app.checked .c-content {
  transform: scale(1.12);
  border-radius: 12px;
  background: var(--font-color-light) !important;
}


.app-icon {
  width: calc(100% - 12px);
  margin: 6px;
  aspect-ratio: 1/1;
}


/* 对话框底部按钮样式 */
.dialog-footer {
  text-align: right;
  margin-top: 20px;
}

.button {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.button.btn-primary {
  background-color: var(--primary-color);
  color: #fff;
}

.button.btn-error {
  background-color: var(--error-color);
  color: #fff;
}

/* 错误消息样式 */
.error-message {
  color: var(--error-color);
  margin: 10px;
  text-align: center;
}

/* 网格项样式 */
.vue-grid-item.vue-grid-placeholder {
  background: red !important;
  border-radius: 16px !important;
}

.vue-grid-item {
  .vue-resizable-handle {
    position: absolute;
    width: 16px !important;
    height: 16px !important;
    bottom: 1px !important;
    right: 1px !important;
    border: 2px transparent solid;
    border-bottom-right-radius: 16px !important;
    background: none !important;
    transition: all 0.2s ease !important;
  }
}

/* 设置面板样式 */
.settings-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 20px;

  * {
    transition: all 0.4s ease;
  }
}

.settings-header {
  margin-bottom: 20px;
  color: #eee;
}

.settings-body {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

.drop-app {
  text-align: center;
  cursor: pointer;
  transition: transform 0.2s ease;
  margin: 0 20px;
  margin-top: 20px;

  &:hover {
    transform: scale(1.1);

    .setting-img {
      opacity: 1;
    }
  }
}

.setting-img {
  height: 100%;
  opacity: 0.8;
}

[theme-mode='dark'] .setting-img.component {
  filter: invert(100%) grayscale(30%);
}

.setting-form {
  background-color: var(--dialog-background-color);
  padding: 4px 24px;
  border-radius: 16px;

  .item {
    margin: 16px;
    display: flex;
    align-items: center;
  }
}
</style>

<style lang="less">
.vue-grid-item.vue-grid-placeholder {
  background: red !important;
  border-radius: 16px !important;
}

.vue-grid-item {
  .vue-resizable-handle {
    position: absolute;
    width: 16px !important;
    height: 16px !important;
    bottom: 1px !important;
    right: 1px !important;
    border: 2px transparent solid;
    border-bottom-right-radius: 16px !important;
    background: none !important;
    transition: all .2s ease !important;
  }

  .vue-resizable-handle:hover {
    border-bottom: 2px #fff solid;
    border-right: 2px #fff solid;
  }

}
</style>

<style></style>